// matrix.h

// Copyright (C) 2010  traxex

// Author: 	traxex <traxex@yahoo.cn>
// Created: 	18 Aug 2010
// Version: 	1.0

#pragma once

#include "../cuda_impl/fft.h"

namespace traxex{
namespace cuda{

template<typename T>
class matrix{
  public:
    uint	Y;
    uint	X;
    T*		_;
    bool	transed;

    matrix( uint y, uint x): Y(y), X(x), _(dmalloc<T>(y*x)), transed(false){}

    matrix():Y(0), X(0), _(0), transed(false){}

    virtual ~matrix(){}

    matrix operator~(){
        matrix tmp = *this;
        tmp.transed = !transed;
        return tmp;
    }
    
    matrix& operator=( T t){
        op_set_k<<<cusize(Y*X)>>>(_, t);
        return *this;
    }

    __device__ T& operator()( uint y, uint x){
        return _[y*X+x];
    }
    
    void _finalize(){
        if( _!=0) dfree( _);
    }

    matrix clone(){
        matrix tmp(Y,X);
        d2dcpy( tmp._, _, Y*X);
        return tmp;
    }
    
    matrix& operator<<( T *h){
	h2dcpy( _, h, Y*X); 
        return *this;
    }
    matrix& operator>>( T *h){	
        d2hcpy( h, _, Y*X);
        return *this;
    }
};
}
}
#include "../cuda_impl/matrix.h"


namespace traxex{
namespace cuda{

template<typename T>void xfft( matrix<T> &out, matrix<T> &in){
    _ensure( out.Y==in.Y && out.X==in.X, "can not do fft matrix(%d,%d)->matrix(%d,%d)", in.Y,in.X,out.Y,out.X);
    fftbase( out._, in._, in.X, -1, in.Y);
}

template<typename T> void xifft( matrix<T> &out, matrix<T> &in){
    _ensure( out.Y==in.Y && out.X==in.X, "can not do ifft matrix(%d,%d)->matrix(%d,%d)", in.Y,in.X,out.Y,out.X);
    fftbase( out._, in._, in.X, 1, in.Y);
}

template<typename T>void fft( matrix<T> &out, matrix<T> &in){
    xfft( out, in);
}

template<typename T> void ifft( matrix<T> &out, matrix<T> &in){
    xifft( out, in);
}

template<typename T> matrix<T> trans( matrix<T> in, matrix<T> out=matrix<T>()){
    if( out._ == 0)	out = matrix<T>(in.Y,in.X);
    _ensure( out.Y==in.X && out.X==in.Y, "can not trans matrix(%d,%d) to matrix(%d,%d)", in.Y,in.X,out.X,out.Y);    
    trans_k<<<cusize(in.Y,in.X)>>>( in, out);
    return out;
}

}
}
